home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP09.ZIP / CHAP09 / PATRON / PAGE.CPP < prev    next >
C/C++ Source or Header  |  1993-06-23  |  24KB  |  1,026 lines

  1. /*
  2.  * PAGE.CPP
  3.  * Modifications for Chapter 9
  4.  *
  5.  * Implementation of parts of the CPage class; those member functions
  6.  * dealing with mouse events are in PAGEMOUS.CPP
  7.  *
  8.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Software Design Engineer
  11.  * Microsoft Systems Developer Relations
  12.  *
  13.  * Internet  :  kraigb@microsoft.com
  14.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  15.  */
  16.  
  17.  
  18. #include "patron.h"
  19.  
  20.  
  21. /*
  22.  * CPage::CPage
  23.  * CPage::~CPage
  24.  *
  25.  * Constructor Parameters:
  26.  *  dwID            DWORD identifier for this page.
  27.  *  hWnd            HWND of the pages window (for repaints, etc).
  28.  *  pPG             LPCPages to the Pages window.
  29.  */
  30.  
  31. CPage::CPage(DWORD dwID, HWND hWnd, LPCPages pPG)
  32.     {
  33.     m_dwID     =dwID;
  34.     m_pIStorage=NULL;
  35.  
  36.     m_cOpens=0;
  37.     m_hWnd=hWnd;
  38.     m_pPG=pPG;
  39.  
  40.     m_dwIDNext      =0;
  41.     m_cTenants      =0;
  42.     m_hWndTenantList=NULL;
  43.     m_iTenantCur    =0xFFFF;    //Tenants are zero indexed.
  44.     m_pTenantCur    =NULL;
  45.  
  46.     m_uHTCode=HTNOWHERE;
  47.     m_uSizingFlags=0;
  48.     m_fTracking=FALSE;
  49.     m_hDC=NULL;
  50.     return;
  51.     }
  52.  
  53.  
  54. CPage::~CPage(void)
  55.     {
  56.     m_hWnd=NULL;
  57.     Close(FALSE);
  58.     return;
  59.     }
  60.  
  61.  
  62.  
  63. /*
  64.  * CPage::GetID
  65.  *
  66.  * Return Value:
  67.  *  DWORD           dwID field in this page.  This function is only here
  68.  *                  to avoid hiding inline implementations in pages.h
  69.  */
  70.  
  71. DWORD CPage::GetID(void)
  72.     {
  73.     return m_dwID;
  74.     }
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81. /*
  82.  * CPage::FOpen
  83.  *
  84.  * Purpose:
  85.  *  Retrieves the IStorage associated with this page.  The IStorage is
  86.  *  owned by the page and thus the page always holds a reference count.
  87.  *  The caller should call ::Close or delete this page to match this open.
  88.  *
  89.  *  This function may be called multiple times resulting in additional
  90.  *  reference counts on the storage each of which must be matched with
  91.  *  a call to ::Close.  The last ::Close can be done through delete.
  92.  *
  93.  * Parameters:
  94.  *  pIStorage       LPSTORAGE in which this page lives.
  95.  *
  96.  * Return Value:
  97.  *  BOOL            TRUE if opening succeeds, FALSE otherwise.
  98.  */
  99.  
  100. BOOL CPage::FOpen(LPSTORAGE pIStorage)
  101.     {
  102.     HRESULT         hr=NOERROR;
  103.     LPSTREAM        pIStream;
  104.     DWORD           dwMode;
  105.     char            szTemp[32];
  106.     BOOL            fNew;
  107.     BOOL            fCreated=FALSE;
  108.     TENANTLIST      tl;
  109.     LPTENANTINFO    pti;
  110.     ULONG           cb;
  111.     LPMALLOC        pIMalloc;
  112.     UINT            i;
  113.     LPTENANT        pTenant;
  114.  
  115.     fNew=(NULL==m_pIStorage);
  116.  
  117.     if (!fNew)
  118.         {
  119.         m_cOpens++;
  120.         m_pIStorage->AddRef();
  121.         return TRUE;
  122.         }
  123.  
  124.     if (NULL==pIStorage)
  125.         return FALSE;
  126.  
  127.     /*
  128.      * Attempt to open the storage under this ID.  If there is none, then
  129.      * create it.  In either case we end up with an IStorage that we
  130.      * either save in pPage or release.
  131.      */
  132.  
  133.     GetStorageName(szTemp);
  134.     dwMode=STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  135.  
  136.     hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0, &m_pIStorage);
  137.  
  138.     if (FAILED(hr))
  139.         {
  140.         hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0, &m_pIStorage);
  141.         fCreated=TRUE;
  142.         }
  143.  
  144.     if (FAILED(hr))
  145.         return FALSE;
  146.  
  147.     m_cOpens++;
  148.  
  149.     if (NULL==m_hWndTenantList)
  150.         {
  151.         /*
  152.          * The first time we open this page, create the hidden listbox
  153.          * we'll use to track tenants.  We give it the owner-draw style
  154.          * so we can just store pointers in it.
  155.          */
  156.         m_hWndTenantList=CreateWindow("listbox", "Tenant List"
  157.             , WS_POPUP | LBS_OWNERDRAWFIXED, 0, 0, 100, 100
  158.             , HWND_DESKTOP, NULL, m_pPG->m_hInst, NULL);
  159.  
  160.         if (NULL==m_hWndTenantList)
  161.             return FALSE;
  162.         }
  163.  
  164.  
  165.     //If this is brand-new, we're done.
  166.     if (fCreated)
  167.         return TRUE;
  168.  
  169.  
  170.     /*
  171.      * Now open the stream we saved in ::Close and load all the
  172.      * tenants listed in there.  If there are none, then we don't
  173.      * have to load squat.
  174.      */
  175.  
  176.     hr=m_pIStorage->OpenStream(SZSTREAMTENANTLIST, NULL, STGM_DIRECT
  177.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  178.  
  179.     if (FAILED(hr))
  180.         return FALSE;
  181.  
  182.     if (SUCCEEDED(CoGetMalloc(MEMCTX_SHARED, &pIMalloc)))
  183.         {
  184.         pIStream->Read((LPVOID)&tl, sizeof(tl), NULL);
  185.         m_cTenants=tl.cTenants;
  186.         m_dwIDNext=tl.dwIDNext;
  187.         m_iTenantCur=0;
  188.  
  189.         cb=tl.cTenants*sizeof(TENANTINFO);
  190.  
  191.         if (0!=cb)
  192.             {
  193.             pti=(LPTENANTINFO)pIMalloc->Alloc(cb);
  194.  
  195.             if (NULL!=pti)
  196.                 {
  197.                 pIStream->Read((LPVOID)pti, cb, NULL);
  198.  
  199.                 for (i=0; i < m_cTenants; i++)
  200.                     {
  201.                     if (FTenantAdd(-1, (pti+i)->dwID, &pTenant))
  202.                         pTenant->FLoad(m_pIStorage, &(pti+i)->fe, &(pti+i)->rcl);
  203.                     }
  204.  
  205.                 pIMalloc->Free((LPVOID)pti);
  206.                 }
  207.             }
  208.  
  209.         pIMalloc->Release();
  210.         }
  211.  
  212.     pIStream->Release();
  213.  
  214.     //Get and select the first tenant
  215.     if (FTenantGet(0, &m_pTenantCur, FALSE))
  216.         m_pTenantCur->Select(TRUE);
  217.  
  218.     return TRUE;
  219.     }
  220.  
  221.  
  222.  
  223.  
  224.  
  225. /*
  226.  * CPage::Close
  227.  *
  228.  * Purpose:
  229.  *  Possibly commits the storage, then releases it reversing the
  230.  *  reference count from FOpen.
  231.  *
  232.  * Parameters:
  233.  *  fCommit         BOOL indicating if we're to commit.
  234.  *
  235.  * Return Value:
  236.  *  None
  237.  */
  238.  
  239. void CPage::Close(BOOL fCommit)
  240.     {
  241.     if (NULL==m_pIStorage)
  242.         return;
  243.  
  244.     if (fCommit)
  245.         Update();
  246.  
  247.     m_pIStorage->Release();
  248.  
  249.     //If this was the last close, make all tenants loaded->passive
  250.     if (0==--m_cOpens)
  251.         {
  252.         UINT        i;
  253.         LPTENANT    pTenant;
  254.  
  255.         m_pIStorage=NULL;
  256.  
  257.         for (i=0; i < m_cTenants; i++)
  258.             {
  259.             if (FTenantGet(i, &pTenant, FALSE))
  260.                 {
  261.                 if (NULL!=m_hWnd)
  262.                     {
  263.                     //FOpen may select again, so this repaints.
  264.                     pTenant->Select(FALSE);
  265.                     }
  266.  
  267.                 pTenant->Close(FALSE);
  268.                 //CHAPTER9MOD
  269.                 pTenant->Release();
  270.                 //End CHAPTER9MOD
  271.                 }
  272.             }
  273.  
  274.         DestroyWindow(m_hWndTenantList);
  275.         m_hWndTenantList=NULL;
  276.         }
  277.  
  278.     return;
  279.     }
  280.  
  281.  
  282.  
  283.  
  284. /*
  285.  * CPage::Update
  286.  *
  287.  * Purpose:
  288.  *  Forces a common on the page if it's open.
  289.  *
  290.  * Parameters:
  291.  *  None
  292.  *
  293.  * Return Value:
  294.  *  BOOL            TRUE if there are any open objects on this page,
  295.  *                  that is, we should remain open.
  296.  */
  297.  
  298. BOOL CPage::Update(void)
  299.     {
  300.     BOOL            fOpen=FALSE;
  301.     UINT            i;
  302.     LPTENANT        pTenant;
  303.     HRESULT         hr;
  304.     LPSTREAM        pIStream;
  305.     TENANTLIST      tl;
  306.     LPTENANTINFO    pti;
  307.     ULONG           cb;
  308.     LPMALLOC        pIMalloc;
  309.  
  310.     //Walk the list of objects and update them all as well.
  311.     for (i=0; i < m_cTenants; i++)
  312.         {
  313.         if (FTenantGet(i, &pTenant, FALSE))
  314.             fOpen |= pTenant->Update();
  315.         }
  316.  
  317.     //Now write our own stream containing the tenant list.
  318.     hr=m_pIStorage->CreateStream(SZSTREAMTENANTLIST, STGM_CREATE | STGM_WRITE
  319.         | STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStream);
  320.  
  321.     if (FAILED(hr))
  322.         return fOpen;
  323.  
  324.     if (SUCCEEDED(CoGetMalloc(MEMCTX_SHARED, &pIMalloc)))
  325.         {
  326.         tl.cTenants=m_cTenants;
  327.         tl.dwIDNext=m_dwIDNext;
  328.  
  329.         pIStream->Write((LPVOID)&tl, sizeof(TENANTLIST), &cb);
  330.  
  331.         cb=m_cTenants*sizeof(TENANTINFO);
  332.         pti=(LPTENANTINFO)pIMalloc->Alloc(cb);
  333.  
  334.         if (NULL!=pti)
  335.             {
  336.             for (i=0; i < m_cTenants; i++)
  337.                 {
  338.                 FTenantGet(i, &pTenant, FALSE);
  339.                 (pti+i)->dwID=pTenant->GetID();
  340.                 pTenant->RectGet(&(pti+i)->rcl, FALSE);
  341.                 pTenant->FormatEtcGet(&(pti+i)->fe, FALSE);
  342.                 }
  343.  
  344.             pIStream->Write((LPVOID)pti, cb, &cb);
  345.             pIMalloc->Free((LPVOID)pti);
  346.             }
  347.  
  348.         pIMalloc->Release();
  349.         }
  350.  
  351.     pIStream->Release();
  352.  
  353.     //Now commit the whole mess and we're done
  354.     if (NULL!=m_pIStorage)
  355.         m_pIStorage->Commit(STGC_ONLYIFCURRENT);
  356.  
  357.     return fOpen;
  358.     }
  359.  
  360.  
  361.  
  362. /*
  363.  * CPage::Destroy
  364.  *
  365.  * Purpose:
  366.  *  Removes this page from the given storage.  The caller should
  367.  *  eventually delete this Page object to free the storage.
  368.  *
  369.  * Parameters:
  370.  *  pIStorage       LPSTORAGE contianing this page on which to call
  371.  *                  ::DestroyElement
  372.  *
  373.  * Return Value:
  374.  *  None
  375.  */
  376.  
  377. void CPage::Destroy(LPSTORAGE pIStorage)
  378.     {
  379.     char        szTemp[32];
  380.  
  381.     if (NULL!=pIStorage)
  382.         {
  383.         if (NULL!=m_pIStorage)
  384.             m_pIStorage->Release();
  385.  
  386.         GetStorageName(szTemp);
  387.         pIStorage->DestroyElement(szTemp);
  388.  
  389.         m_pIStorage=NULL;
  390.         }
  391.  
  392.     return;
  393.     }
  394.  
  395.  
  396.  
  397.  
  398.  
  399. /*
  400.  * CPage::GetStorageName
  401.  *
  402.  * Parameters:
  403.  *  pszName         LPSTR to a buffer in which to store the storage name
  404.  *                  for this page.
  405.  *
  406.  * Return Value:
  407.  *  UINT            Number of characters stored.
  408.  */
  409.  
  410. UINT CPage::GetStorageName(LPSTR pszName)
  411.     {
  412.     return wsprintf(pszName, "Page %lu", m_dwID);
  413.     }
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420. /*
  421.  * CPage::Draw
  422.  *
  423.  * Purpose:
  424.  *  Draws the objects on this page to the given hDC.
  425.  *
  426.  * Parameters:
  427.  *  hDC             HDC on which to draw.
  428.  *  xOff, yOff      int offsets for the page.
  429.  *  fNoColor        BOOL indicating a black & white screen rendering.
  430.  *  fPrinter        BOOL indicating hDC is on the printer.
  431.  *
  432.  * Return Value:
  433.  *  None
  434.  */
  435.  
  436. void CPage::Draw(HDC hDC, int xOff, int yOff, BOOL fNoColor, BOOL fPrinter)
  437.     {
  438.     int                 i;
  439.     LPTENANT            pTenant;
  440.     HDC                 hIC=NULL;
  441.     DVTARGETDEVICE FAR *ptd=NULL;
  442.  
  443.     /*
  444.      * This local structure eliminates having to allocate the
  445.      * DVTARGETDEVICE structure separately.  We can just stuff its
  446.      * fields with offsets to the DEVICECONFIG structure and the
  447.      * characters arrays.
  448.      */
  449.     struct
  450.         {
  451.         DVTARGETDEVICE  td;
  452.         DEVICECONFIG    dc;
  453.         } dev;
  454.  
  455.  
  456.     /*
  457.      * If printing, tell the tenant to forget the borders.  Otherwise
  458.      * we leave xOff and yOff the same to account for scrolling.
  459.      */
  460.     if (fPrinter)
  461.         {
  462.         xOff=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  463.         yOff=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  464.  
  465.         /*
  466.          * Create a DVTARGETDEVICE structure.  If this fails, we just
  467.          * pass ptd to CTenant::Draw, which is acceptable.
  468.          */
  469.         if (m_pPG->DevReadConfig(&dev.dc, &hIC))
  470.             {
  471.             WORD    cb=sizeof(DVTARGETDEVICE);
  472.  
  473.             dev.td.tdSize=cb;
  474.             dev.td.tdExtDevmodeOffset=cb;
  475.             dev.td.tdDriverNameOffset=cb+sizeof(DEVMODE);
  476.             dev.td.tdDeviceNameOffset=cb+sizeof(DEVMODE)+CCHDEVICENAME;
  477.             dev.td.tdPortNameOffset  =cb+sizeof(DEVMODE)+(CCHDEVICENAME*2);
  478.  
  479.             ptd=&dev.td;
  480.             }
  481.         }
  482.  
  483.     for (i=(int)m_cTenants-1; i >=0; i--)
  484.         {
  485.         if (FTenantGet(i, &pTenant, FALSE))
  486.             {
  487.             RECT        rc, rcWin;
  488.             RECTL       rcl;
  489.  
  490.             //Paint this tenant only if visible.
  491.             pTenant->RectGet(&rcl, TRUE);
  492.             RECTFROMRECTL(rc, rcl);
  493.             OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  494.             GetClientRect(m_hWnd, &rcWin);
  495.  
  496.             if (IntersectRect(&rc, &rc, &rcWin))
  497.                 pTenant->Draw(hDC, ptd, hIC, xOff, yOff, fNoColor, fPrinter);
  498.             }
  499.         }
  500.  
  501.     if (NULL!=hIC)
  502.         DeleteDC(hIC);
  503.  
  504.     return;
  505.     }
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512. /*
  513.  * CPage::TenantCreate
  514.  *
  515.  * Purpose:
  516.  *  Creates a new tenant of a specific type.
  517.  *
  518.  * Parameters:
  519.  *  tType           TENANTTYPE to create.
  520.  *  pv              LPVOID providing information for the new object creation.
  521.  *  pFE             LPFORMATETC describing how we want this rendered.
  522.  *  ppo             LPPATRONOBJECT with placement data.
  523.  *  dwData          DWORD extra data to pass to the tenant.
  524.  *
  525.  * Return Value:
  526.  *  None
  527.  */
  528.  
  529. BOOL CPage::TenantCreate(TENANTTYPE tType, LPVOID pv, LPFORMATETC pFE
  530.     , LPPATRONOBJECT ppo, DWORD dwData)
  531.     {
  532.     LPTENANT    pTenant;
  533.     UINT        uRet;
  534.     int         x, y;
  535.     int         h, v;
  536.     POINTL      ptl;
  537.     SIZEL       szl;
  538.     RECTL       rcl;
  539.     RECT        rc;
  540.  
  541.     //New tenants go at the top of the pile, so zero index to FTenantAdd.
  542.     if (!FTenantAdd(0, m_dwIDNext, &pTenant))
  543.         return FALSE;
  544.  
  545.     uRet=pTenant->UCreate(tType, pv, pFE, &ptl, &szl, m_pIStorage, ppo, dwData);
  546.  
  547.     if (UCREATE_FAILED==uRet)
  548.         {
  549.         //Reverse UCreate AND FTenantAdd
  550.         SendMessage(m_hWndTenantList, LB_DELETESTRING, 0, 0L);
  551.         pTenant->Destroy(m_pIStorage);
  552.  
  553.         //CHAPTER9MOD
  554.         pTenant->Release();
  555.         //End CHAPTER9MOD
  556.         return FALSE;
  557.         }
  558.  
  559.     m_dwIDNext++;
  560.     m_cTenants++;
  561.  
  562.     if (NULL!=m_pTenantCur)
  563.         m_pTenantCur->Select(FALSE);
  564.  
  565.     m_iTenantCur=0;             //First one in the list now.
  566.     m_pTenantCur=pTenant;
  567.  
  568.     //Tell the tenant where it lives, default is at (0,0) in print area
  569.     x=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  570.     y=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  571.  
  572.     h=x;
  573.     v=y;
  574.  
  575.     if (UCREATE_PLACEDOBJECT==uRet)
  576.         {
  577.         SetRect(&rc, 3*CXYHANDLE, 3*CXYHANDLE, 0, 0);
  578.         RectConvertMappings(&rc, NULL, FALSE);
  579.  
  580.         //Make sure the place point is on the page, otherwise go to (0,0)
  581.         if (((int)ptl.x > x) && ((int)ptl.x < x+(int)m_pPG->m_cx-rc.left))
  582.             x=(int)ptl.x;
  583.  
  584.         //m_pPG->m_cy is absolute
  585.         if (((int)ptl.y < y) && ((int)ptl.y > y-(int)m_pPG->m_cy-rc.top))
  586.             y=(int)ptl.y;
  587.         }
  588.  
  589.     //Bounds check the size of the object and fit to page as necessary.
  590.     if (x+(int)szl.cx > (int)(h+m_pPG->m_cx))
  591.         szl.cx=h+m_pPG->m_cx-x;
  592.  
  593.     //Remember that szl we get from UCreate is absolute
  594.     if (y-(int)szl.cy < (int)(v-m_pPG->m_cy))
  595.         szl.cy=-(int)(v-m_pPG->m_cy-y);
  596.  
  597.     SETRECTL(rcl, x, y, x+szl.cx, y-szl.cy);
  598.     m_pTenantCur->RectSet(&rcl, FALSE);
  599.  
  600.     //Force a repaint on this new guy
  601.     m_pTenantCur->Invalidate();
  602.     UpdateWindow(m_hWnd);
  603.  
  604.     m_pTenantCur->Select(TRUE);
  605.  
  606.     //CHAPTER9MOD
  607.     //Activate new objects immediately and force a save on them
  608.     if (TENANTTYPE_EMBEDDEDOBJECT==tType)
  609.         {
  610.         m_pTenantCur->Activate(OLEIVERB_SHOW);
  611.         m_pTenantCur->Update();
  612.         }
  613.     //End CHAPTER9MOD
  614.  
  615.     return TRUE;
  616.     }
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623. /*
  624.  * CPage::TenantDestroy
  625.  *
  626.  * Purpose:
  627.  *  Destroys the currently selected tenant on this page.
  628.  *
  629.  * Parameters:
  630.  *  None
  631.  *
  632.  * Return Value:
  633.  *  None
  634.  */
  635.  
  636. BOOL CPage::TenantDestroy(void)
  637.     {
  638.     if (NULL==m_pTenantCur)
  639.         {
  640.         MessageBeep(0);
  641.         return FALSE;
  642.         }
  643.  
  644.     SendMessage(m_hWndTenantList, LB_DELETESTRING, m_iTenantCur, 0L);
  645.  
  646.     m_pTenantCur->Invalidate();
  647.     m_pTenantCur->Destroy(m_pIStorage);
  648.  
  649.     delete m_pTenantCur;
  650.     m_pTenantCur=NULL;
  651.  
  652.     //Update counts, etc., and select the next tenant in the list.
  653.     if (m_iTenantCur==m_cTenants-1)
  654.         m_iTenantCur--;
  655.  
  656.     if (0==--m_cTenants)
  657.         m_pTenantCur=NULL;
  658.     else
  659.         {
  660.         FTenantGet(m_iTenantCur, &m_pTenantCur, TRUE);
  661.         m_pTenantCur->Select(TRUE);
  662.         }
  663.  
  664.     UpdateWindow(m_hWnd);
  665.     return TRUE;
  666.     }
  667.  
  668.  
  669.  
  670.  
  671.  
  672. /*
  673.  * CPage::TenantClip
  674.  *
  675.  * Purpose:
  676.  *  Copies or cuts the currently selected tenant to the clipoard.
  677.  *
  678.  * Parameters:
  679.  *  fCut            BOOL TRUE to cut the object, FALSE to copy.
  680.  *
  681.  * Return Value:
  682.  *  BOOL            TRUE if successful, FALSE otherwise.
  683.  */
  684.  
  685. BOOL CPage::TenantClip(BOOL fCut)
  686.     {
  687.     LPDATAOBJECT    pIDataObject;
  688.  
  689.     if (NULL==m_pTenantCur)
  690.         return FALSE;
  691.  
  692.     /*
  693.      * To perform a data transfer operation, we need to create a
  694.      * data object with the selected object's data inside. To do
  695.      * this we CoCreateInstance on CLSID_DataTransferObject
  696.      * (Also implemented in this chapter), retrieve data from the
  697.      * object we have, stuff that data into the transfer object,
  698.      * then stick that object on the clipboard.
  699.      *
  700.      * Since we'll want an identical object at other times, like
  701.      * for drag-drop, we use a private function to actually create it.
  702.      */
  703.  
  704.     pIDataObject=TransferObjectCreate(NULL);
  705.  
  706.     if (NULL!=pIDataObject)
  707.         {
  708.         if (SUCCEEDED(OleSetClipboard(pIDataObject)))
  709.             {
  710.             if (fCut)
  711.                 TenantDestroy();
  712.  
  713.             return TRUE;
  714.             }
  715.  
  716.         pIDataObject->Release();
  717.         }
  718.  
  719.     return FALSE;
  720.     }
  721.  
  722.  
  723.  
  724.  
  725.  
  726. /*
  727.  * CPage::FQueryObjectSelected
  728.  *
  729.  * Purpose:
  730.  *  Returns whether or not there is an object selected on this
  731.  *  page for Cut, Copy, Delete functions.  This is specifically
  732.  *  used to enable menu items.
  733.  *
  734.  * Parameters:
  735.  *  hMenu           HMENU of the menu on which object related items live.
  736.  *
  737.  * Return Value:
  738.  *  BOOL            TRUE if we have an object, FALSE otherwise.
  739.  */
  740.  
  741. BOOL CPage::FQueryObjectSelected(HMENU hMenu)
  742.     {
  743.     //CHAPTER9MOD
  744.     HMENU       hMenuTemp;
  745.  
  746.     /*
  747.      * This will only be called on WM_INITMENUPOPUP, we'll also use this
  748.      * function to create the Verb menu for this object.
  749.      */
  750.     if (NULL!=m_pTenantCur)
  751.         {
  752.         m_pTenantCur->AddVerbMenu(hMenu, MENUPOS_OBJECT);
  753.         return TRUE;
  754.         }
  755.  
  756.     OleUIAddVerbMenu(NULL, NULL, hMenu, MENUPOS_OBJECT
  757.         , IDM_VERBMIN, FALSE, 0, &hMenuTemp);
  758.  
  759.     return FALSE;
  760.     //End CHAPTER9MOD
  761.     }
  762.  
  763.  
  764.  
  765. //CHAPTER9MOD
  766. /*
  767.  * CPage::ActivateObject
  768.  *
  769.  * Purpose:
  770.  *  Executes a verb on the currently selected object.
  771.  *
  772.  * Parameters:
  773.  *  iVerb           UINT of the selected verb.
  774.  *
  775.  * Return Value:
  776.  *  None
  777.  */
  778.  
  779. void CPage::ActivateObject(UINT iVerb)
  780.     {
  781.     if (NULL==m_pTenantCur)
  782.         return;
  783.  
  784.     m_pTenantCur->Activate(iVerb);
  785.     return;
  786.     }
  787.  
  788.  
  789.  
  790. /*
  791.  * CPage::NotifyTenantsOfRename
  792.  *
  793.  * Purpose:
  794.  *  Loops through all the tenants and informs each of the new document name.
  795.  *
  796.  * Parameters:
  797.  *  pszFile         LPSTR of the new filename.
  798.  *  pvReserved      LPVOID reserved for future use.
  799.  *
  800.  * Return Value:
  801.  *  None
  802.  */
  803.  
  804. void CPage::NotifyTenantsOfRename(LPSTR pszFile, LPVOID pvReserved)
  805.     {
  806.     LPTENANT    pTenant;
  807.     UINT        i;
  808.  
  809.     for (i=0; i < m_cTenants; i++)
  810.         {
  811.         if (FTenantGet(i, &pTenant, FALSE))
  812.             pTenant->NotifyOfRename(pszFile, pvReserved);
  813.         }
  814.  
  815.     return;
  816.     }
  817.  
  818. //End CHAPTER9MOD
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825. /*
  826.  * CPages::FTenantGet
  827.  * (Protected)
  828.  *
  829.  * Purpose:
  830.  *  Returns a tenant of a given index returning a BOOL so it's simple
  831.  *  to use this function inside if statements.
  832.  *
  833.  * Parameters:
  834.  *  iTenant         UINT tenant to retrieve 0 based.
  835.  *  ppTenant        LPPAGE FAR * in which to return the tenant pointer
  836.  *  fOpen           BOOL indicating if we should open this tenant as well.
  837.  *
  838.  * Return Value:
  839.  *  BOOL            TRUE if successful, FALSE otherwise.
  840.  */
  841.  
  842. BOOL CPage::FTenantGet(UINT iTenant, LPTENANT FAR *ppTenant, BOOL fOpen)
  843.     {
  844.     if (NULL==ppTenant)
  845.         return FALSE;
  846.  
  847.     if (sizeof(LPTENANT)==SendMessage(m_hWndTenantList, LB_GETTEXT, iTenant
  848.         , (LONG)(LPVOID)ppTenant))
  849.         {
  850.         if (fOpen)
  851.             (*ppTenant)->FOpen(m_pIStorage);
  852.  
  853.         return TRUE;
  854.         }
  855.  
  856.     return FALSE;
  857.     }
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865. /*
  866.  * CPage::FTenantAdd
  867.  * (Protected)
  868.  *
  869.  * Purpose:
  870.  *  Creates a new tenant initialized to the given values.  The new tenants's
  871.  *  storage is created if it does not already exist.  If fOpenStorage
  872.  *  is set the the tenants's storage is opened and left opened.
  873.  *
  874.  * Parameters:
  875.  *  iTenant         UINT Location at which to insert tenant; new tenant is
  876.  *                  inserted after this position.  0xFFFF for the end.
  877.  *  dwID            DWORD ID for this tenant.
  878.  *  ppNew           LPTENANT FAR * in which to store the new tenant.
  879.  *
  880.  * Return Value:
  881.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  882.  */
  883.  
  884. BOOL CPage::FTenantAdd(UINT iTenant, DWORD dwID, LPTENANT FAR *ppNew)
  885.     {
  886.     LPTENANT    pTenant;
  887.     LRESULT     lr;
  888.  
  889.     if (NULL!=ppNew)
  890.         *ppNew=NULL;
  891.  
  892.     pTenant=new CTenant(dwID, m_hWnd, m_pPG);
  893.  
  894.     if (NULL==pTenant)
  895.         return FALSE;
  896.  
  897.     //CHAPTER9MOD
  898.     //The constructor doesn't AddRef, so we need to as an understanding.
  899.     pTenant->AddRef();
  900.     //End CHAPTER9MOD
  901.  
  902.     //Now try to add to the listbox.
  903.     lr=SendMessage(m_hWndTenantList, LB_INSERTSTRING, iTenant, (LONG)pTenant);
  904.  
  905.     if (lr < 0)
  906.         {
  907.         pTenant->Release();
  908.         return FALSE;
  909.         }
  910.  
  911.     *ppNew=pTenant;
  912.     return TRUE;
  913.     }
  914.  
  915.  
  916.  
  917.  
  918.  
  919. /*
  920.  * CPage::TransferObjectCreate
  921.  * (Protected)
  922.  *
  923.  * Purpose:
  924.  *  Creates a DataTransferObject and stuff the current selection's
  925.  *  data into it.
  926.  *
  927.  * Parameters:
  928.  *  pptl            LPPOINTL containing the pick point in device units
  929.  *                  applicable only to drag-drop; since drag-drop is
  930.  *                  inherently mouse oriented, we use device units for
  931.  *                  the point.  Ignored if NULL.
  932.  *
  933.  * Return Value:
  934.  *  LPDATAOBJECT    Pointer to the object created, NULL on failure
  935.  */
  936.  
  937. LPDATAOBJECT CPage::TransferObjectCreate(LPPOINTL pptl)
  938.     {
  939.     LPDATAOBJECT    pIDataObject;
  940.     LPDATAOBJECT    pIDataT;
  941.     LPPATRONOBJECT  ppo;
  942.     RECTL           rcl;
  943.     LPUNKNOWN       pObj;
  944.     FORMATETC       fe;
  945.     STGMEDIUM       stm;
  946.     HRESULT         hr;
  947.  
  948.     m_pTenantCur->ObjectGet(&pObj);
  949.  
  950.     hr=CoCreateInstance(CLSID_DataTransferObject, NULL, CLSCTX_INPROC_SERVER
  951.         , IID_IDataObject, (LPVOID FAR *)&pIDataObject);
  952.  
  953.     if (FAILED(hr))
  954.         return NULL;
  955.  
  956.     //Go get the data we should hold on to.
  957.     hr=pObj->QueryInterface(IID_IDataObject, (LPVOID FAR *)&pIDataT);
  958.  
  959.     if (FAILED(hr))
  960.         {
  961.         pIDataObject->Release();
  962.         pObj->Release();
  963.         return NULL;
  964.         }
  965.  
  966.     //Copy from known object into transfer object.  Ordering is important!
  967.  
  968.     //Generate placeable object structure
  969.     stm.tymed=TYMED_HGLOBAL;
  970.     stm.pUnkForRelease=NULL;
  971.     stm.hGlobal=GlobalAlloc(GHND, sizeof(PATRONOBJECT));
  972.  
  973.     if (NULL==stm.hGlobal)
  974.         {
  975.         pIDataObject->Release();
  976.         pObj->Release();
  977.         return NULL;
  978.         }
  979.  
  980.     ppo=(LPPATRONOBJECT)GlobalLock(stm.hGlobal);
  981.  
  982.     m_pTenantCur->SizeGet(&ppo->szl, FALSE);
  983.     ppo->szl.cy=-ppo->szl.cy; //Negate to make absolute size
  984.  
  985.     m_pTenantCur->RectGet(&rcl, FALSE);
  986.     ppo->ptl.x=rcl.left;
  987.     ppo->ptl.y=rcl.top;
  988.  
  989.     if (NULL==pptl)
  990.         {
  991.         ppo->ptlPick.x=0;
  992.         ppo->ptlPick.y=0;
  993.         }
  994.     else
  995.         ppo->ptlPick=*pptl;
  996.  
  997.     m_pTenantCur->FormatEtcGet(&ppo->fe, FALSE);
  998.  
  999.     //CHAPTER9MOD
  1000.     SETDefFormatEtc(fe, m_pPG->m_cf, TYMED_HGLOBAL);
  1001.     pIDataObject->SetData(&fe, &stm, TRUE);
  1002.  
  1003.     /*
  1004.      * Here now we have to include CF_EMBEDDEDOBJECT when what we
  1005.      * have selected is, in fact, a compound document object.  We'll
  1006.      * just ask the tenant to set it in pIDataObject since it knows
  1007.      * what it has in it.  If we do copy embedded object data, make sure
  1008.      * the PATRONOBJECT structure has the right format in it as well.
  1009.      */
  1010.     m_pTenantCur->CopyEmbeddedObject(pIDataObject, &ppo->fe, pptl);
  1011.  
  1012.     GlobalUnlock(stm.hGlobal);
  1013.     //End CHAPTER9MOD
  1014.  
  1015.     //Copy the actual presentation.
  1016.     m_pTenantCur->FormatEtcGet(&fe, TRUE);
  1017.  
  1018.     pIDataT->GetData(&fe, &stm);
  1019.     pIDataObject->SetData(&fe, &stm, TRUE);
  1020.  
  1021.     pIDataT->Release();
  1022.  
  1023.     pObj->Release();
  1024.     return pIDataObject;    //Caller now responsible
  1025.     }
  1026.